using System;
using System.ComponentModel;
using System.Globalization;
using System.Text.RegularExpressions;

namespace Microsoft.WowAddonStudio.FrameXml.Serialization.TypeConverters
{
	/// <summary>
	/// Provides a type converter to convert expandable objects to and from various other representations.
	/// </summary>
	public class TexCoordsTypeConverter: ExpandableObjectConverter
	{
		private static readonly Regex insetStringRegex;
		private const char listSeparatorMain = ';';
        private const char listSeparator = ',';

		/// <summary>
		/// Initializes the <see cref="InsetTypeConverter"/> class.
		/// </summary>
		static TexCoordsTypeConverter()
		{
            //var regExstring = @"^(([-+]?[0-9]*\%DECIMALSEPARATOR%?[0-9]+)%LISTSEPARATOR%){3}(([-+]?[0-9]*\%DECIMALSEPARATOR%?[0-9]+)%LISTSEPARATOR%{0,1}){1}$";
            var regExstring = @"^([-+]?[0-9]*\%DECIMALSEPARATOR%?[0-9]+%LISTSEPARATOR%[-+]?[0-9]*\%DECIMALSEPARATOR%?[0-9]+%LISTSEPARATORMAIN%[-+]?[0-9]*\%DECIMALSEPARATOR%?[0-9]+%LISTSEPARATOR%[-+]?[0-9]*\%DECIMALSEPARATOR%?[0-9]+){1}$";
            regExstring = regExstring.Replace("%DECIMALSEPARATOR%", CultureInfo.CurrentCulture.NumberFormat.NumberDecimalSeparator);
			regExstring = regExstring.Replace("%LISTSEPARATOR%", listSeparator.ToString());
            regExstring = regExstring.Replace("%LISTSEPARATORMAIN%", listSeparatorMain.ToString());
			insetStringRegex = new Regex(regExstring, RegexOptions.Compiled);
		}

		/// <summary>
		/// Returns whether this converter can convert the object to the specified type, using the specified context.
		/// </summary>
		/// <param name="context">An <see cref="T:System.ComponentModel.ITypeDescriptorContext"/> that provides a format context.</param>
		/// <param name="destinationType">A <see cref="T:System.Type"/> that represents the type you want to convert to.</param>
		/// <returns>
		/// true if this converter can perform the conversion; otherwise, false.
		/// </returns>
		public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType)
		{
			if (destinationType == typeof (Inset))
				return true;

			return base.CanConvertTo(context, destinationType);
		}

		/// <summary>
		/// Returns whether this converter can convert an object of the given type to the type of this converter, using the specified context.
		/// </summary>
		/// <param name="context">An <see cref="T:System.ComponentModel.ITypeDescriptorContext"/> that provides a format context.</param>
		/// <param name="sourceType">A <see cref="T:System.Type"/> that represents the type you want to convert from.</param>
		/// <returns>
		/// true if this converter can perform the conversion; otherwise, false.
		/// </returns>
		public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
		{
			if (sourceType == typeof (string))
				return true;

			return base.CanConvertFrom(context, sourceType);
		}

		/// <summary>
		/// Converts the given value object to the specified type, using the specified context and culture information.
		/// </summary>
		/// <returns>
		/// An <see cref="T:System.Object"></see> that represents the converted value.
		/// </returns>
		/// <param name="culture">A <see cref="T:System.Globalization.CultureInfo"></see>. If null is passed, the current culture is assumed. </param>
		/// <param name="context">An <see cref="T:System.ComponentModel.ITypeDescriptorContext"></see> that provides a format context. </param>
		/// <param name="destinationType">The <see cref="T:System.Type"></see> to convert the value parameter to. </param>
		/// <param name="value">The <see cref="T:System.Object"></see> to convert. </param>
		/// <exception cref="T:System.NotSupportedException">The conversion cannot be performed. </exception>
		/// <exception cref="T:System.ArgumentNullException">The destinationType parameter is null. </exception>
		public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value,
		                                 Type destinationType)
		{
			if ((destinationType == typeof(String)) && (value is TexCoords))
			{
				var inset = (TexCoords)value;
                return String.Format(culture, "{0}{4}{1}{5}{2}{4}{3}", inset.Left, inset.Top, inset.Right, inset.Bottom,
				                     listSeparator,listSeparatorMain);
			}
			return base.ConvertTo(context, culture, value, destinationType);
		}

		/// <summary>
		/// Converts the given object to the type of this converter, using the specified context and culture information.
		/// </summary>
		/// <returns>
		/// An <see cref="T:System.Object"></see> that represents the converted value.
		/// </returns>
		/// <param name="culture">The <see cref="T:System.Globalization.CultureInfo"></see> to use as the current culture. </param>
		/// <param name="context">An <see cref="T:System.ComponentModel.ITypeDescriptorContext"></see> that provides a format context. </param>
		/// <param name="value">The <see cref="T:System.Object"></see> to convert. </param>
		/// <exception cref="T:System.NotSupportedException">The conversion cannot be performed. </exception>
		public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
		{
			if (value is string)
			{
				var textValue = (string) value;
                if (!string.IsNullOrEmpty(textValue))
                {
                    Match match = insetStringRegex.Match(textValue);

                    if (!match.Success)
                    {
                        //float singleValue;
                        //if (float.TryParse(textValue, NumberStyles.Any, culture, out singleValue))
                        //{
                        //    return new TexCoords(singleValue);
                        //}
                        throw new ArgumentException(String.Format(CultureInfo.InvariantCulture, "Invalid TexCoords. (use: [Left]{0}[Top]{1}[Bottom]{0}[Right])", listSeparator,listSeparatorMain));
                    }

                    
                    string[] insetValues = textValue.Split(listSeparator,listSeparatorMain);
                    return new TexCoords(float.Parse(insetValues[0]), float.Parse(insetValues[1]), float.Parse(insetValues[2]),
                                         float.Parse(insetValues[3]));
                }
                else
                {
                    return null;
                }
			}
			return base.ConvertFrom(context, culture, value);
		}
	}
}